package com.zzz.bayer

import android.graphics.Bitmap
import android.util.Log

object BayerHelper {
    /**
     * 简单阈值比较算法
     *
     * @param grayBitmap ARGB_8888 灰度图片R=G=B
     */
    fun easyDither(grayBitmap: Bitmap): Bitmap {
        val width = grayBitmap.width
        val height = grayBitmap.height
        val bayerArray = IntArray(width * height)
        //
        val sourceArray = IntArray(width * height)
        grayBitmap.getPixels(sourceArray, 0, width, 0, 0, width, height)
        sourceArray.forEachIndexed { index, pixel ->
            //灰度图,red = green = blue RGB(gray,gray,gray),取blue = gray
            bayerArray[index] = if (pixel and 0x000000FF >= 128) {
                1
            } else {
                0
            }
        }
        val resultArray = bayerArray.map {
            if (it == 1) {
                0xFFFFFFFF.toInt()
            } else {
                0xFF000000.toInt()
            }
        }.toIntArray()
        //
        val resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        resultBitmap.setPixels(resultArray, 0, width, 0, 0, width, height)
        return resultBitmap
    }

    /**
     * otsu自适应阈值比较算法(最大类间差法)
     *
     * @param grayBitmap ARGB_8888 灰度图片R=G=B
     */
    fun otsuDither(grayBitmap: Bitmap): Bitmap {
        val width = grayBitmap.width
        val height = grayBitmap.height
        val resultArray = IntArray(width * height)
        //


        //
        val resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        resultBitmap.setPixels(resultArray, 0, width, 0, 0, width, height)
        return resultBitmap
    }


    /**
     * 有序抖动算法
     *
     * @param grayBitmap ARGB_8888 灰度图片R=G=B
     */
    fun orderDither(grayBitmap: Bitmap): Bitmap {
        val width = grayBitmap.width
        val height = grayBitmap.height
        val bayerArray = IntArray(width * height)
        //bayer抖动矩阵
        val bayerPattern = arrayOf(
            arrayOf(0, 32, 8, 40, 2, 34, 10, 42),
            arrayOf(48, 16, 56, 24, 50, 18, 58, 26),
            arrayOf(12, 44, 4, 36, 14, 46, 6, 38),
            arrayOf(60, 28, 52, 20, 62, 30, 54, 22),
            arrayOf(3, 35, 11, 43, 1, 33, 9, 41),
            arrayOf(51, 19, 59, 27, 49, 17, 57, 25),
            arrayOf(15, 47, 7, 39, 13, 45, 5, 37),
            arrayOf(63, 31, 55, 23, 61, 29, 53, 21)
        )
        //
        val sourceArray = IntArray(width * height)
        grayBitmap.getPixels(sourceArray, 0, width, 0, 0, width, height)
        for (h in 0 until height) {
            for (w in 0 until width) {
                val index = width * h + w
                val grayPixel = sourceArray[index] and 0x000000FF
                val x = w % 8
                val y = h % 8
                bayerArray[index] = if (grayPixel / 4 >= bayerPattern[x][y]) {
                    1
                } else {
                    0
                }
            }
        }
        //
        val resultArray = bayerArray.map {
            if (it == 1) {
                0xFFFFFFFF.toInt()
            } else {
                0xFF000000.toInt()
            }
        }.toIntArray()
        val resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        resultBitmap.setPixels(resultArray, 0, width, 0, 0, width, height)
        return resultBitmap
    }

    /**
     * 误差扩散算法_Floyd
     *
     * @param grayBitmap ARGB_8888 灰度图片R=G=B
     */
    fun errorDiffusionFloyd(grayBitmap: Bitmap): Bitmap {
        val width = grayBitmap.width
        val height = grayBitmap.height
        val bayerArray = IntArray(width * height)
        //
        val sourceArray = IntArray(width * height)
        grayBitmap.getPixels(sourceArray, 0, width, 0, 0, width, height)
        //转化成8bit灰度值数组,并转成浮点数进行运算，避免因为精度导致误差扩大
        val grayArray = sourceArray.map {
            it and 0x000000FF
        }.map {
            it.toFloat()
        }.toFloatArray()
        for (h in 0 until height) {
            for (w in 0 until width) {
                val index = width * h + w
                val grayPixel = grayArray[index]
                var error: Float //误差
                bayerArray[index] = if (grayPixel >= 128) {
                    error = grayPixel - 255
                    1
                } else {
                    error = grayPixel
                    0
                }
                //将误差扩散到相邻点
                if (h + 1 < height && w + 1 < width && w - 1 >= 0) {
                    grayArray[width * h + w + 1] += error * 7 / 16
                    grayArray[width * (h + 1) + w - 1] += error * 3 / 16
                    grayArray[width * (h + 1) + w] += error * 5 / 16
                    grayArray[width * (h + 1) + w + 1] += error * 1 / 16
                } else if (h + 1 < height && w - 1 < 0) {
                    grayArray[width * h + w + 1] += error * 7 / 16
                    grayArray[width * (h + 1) + w] += error * 5 / 16
                    grayArray[width * (h + 1) + w + 1] += error * 1 / 16
                } else if (h + 1 < height && w + 1 >= width) {
                    grayArray[width * (h + 1) + w - 1] += error * 3 / 16
                    grayArray[width * (h + 1) + w] += error * 5 / 16
                } else if (h + 1 >= height && w + 1 < width) {
                    grayArray[width * h + w + 1] += error * 7 / 16
                }
            }
        }
        //
        val resultArray = bayerArray.map {
            if (it == 1) {
                0xFFFFFFFF.toInt()
            } else {
                0xFF000000.toInt()
            }
        }.toIntArray()
        val resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        resultBitmap.setPixels(resultArray, 0, width, 0, 0, width, height)
        return resultBitmap
    }

    /**
     * 点扩散算法
     */
    fun dotDiffusion(grayBitmap: Bitmap): Bitmap {
        val width = grayBitmap.width
        val height = grayBitmap.height
        val resultArray = IntArray(width * height)
        //
        val resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        resultBitmap.setPixels(resultArray, 0, width, 0, 0, width, height)
        return resultBitmap
    }
}

